package top.codedance.iotp.converter.service.slave.holder;

import top.codedance.iotp.converter.ConverterApplication;
import com.intelligt.modbus.jlibmodbus.data.DataHolder;
import com.intelligt.modbus.jlibmodbus.data.ModbusCoils;
import com.intelligt.modbus.jlibmodbus.data.ModbusHoldingRegisters;
import com.intelligt.modbus.jlibmodbus.exception.IllegalDataAddressException;
import com.intelligt.modbus.jlibmodbus.exception.IllegalDataValueException;
import com.intelligt.modbus.jlibmodbus.exception.IllegalFunctionException;
import com.intelligt.modbus.jlibmodbus.utils.DataUtils;
import org.apache.log4j.Logger;

public class RtuDataHolder extends DataHolder {
    private Logger logger = ConverterApplication.getLogger(RtuDataHolder.class);

    @Override
    public int readHoldingRegister(int offset) throws IllegalDataAddressException {
        logger.debug("readHoldingRegister");
        if (ConverterApplication.master != null) {
            ModbusHoldingRegisters holdingRegisters = super.getHoldingRegisters();
            if (holdingRegisters != null) {
                writeLocalOfRead(offset, 1, holdingRegisters);
            }
        }
        return super.readHoldingRegister(offset);
    }

    @Override
    public int[] readHoldingRegisterRange(int offset, int quantity) throws IllegalDataAddressException {
        logger.debug("readHoldingRegisterRange");
        if (ConverterApplication.master != null) {
            ModbusHoldingRegisters holdingRegisters = super.getHoldingRegisters();
            if (holdingRegisters != null) {
                writeLocalOfRead(offset, quantity, holdingRegisters);
            }
        }
        return super.readHoldingRegisterRange(offset, quantity);
    }

    @Override
    public int[] readInputRegisterRange(int offset, int quantity) throws IllegalDataAddressException {
        logger.debug("readInputRegisterRange");
        if (ConverterApplication.master != null) {
            ModbusHoldingRegisters inputRegisters = super.getInputRegisters();
            if (inputRegisters != null) {
                writeLocalOfRead(offset, quantity, inputRegisters);
            }
        }
        return super.readInputRegisterRange(offset, quantity);
    }

    @Override
    public boolean[] readCoilRange(int offset, int quantity) throws IllegalDataAddressException, IllegalDataValueException {
        logger.debug("readCoilRange");
        if (ConverterApplication.master != null) {
            boolean[] booleans = ConverterApplication.master.readCoilRange(offset, quantity);
            if (booleans != null) {
                ModbusCoils coils = super.getCoils();
                if (coils != null) {
                    for (int i = offset; i < quantity; i++) {
                        coils.set(i, booleans[i]);
                    }
                }
            }
        }
        return super.readCoilRange(offset, quantity);
    }

    @Override
    public byte[] readSlaveId() throws IllegalFunctionException {
        logger.debug("readSlaveId");
        return super.getSlaveId().get();
    }

    @Override
    public void writeHoldingRegister(int offset, int value) throws IllegalDataAddressException, IllegalDataValueException {
        logger.debug("writeHoldingRegister");
        if (ConverterApplication.master != null) {
            ConverterApplication.master.writeHoldingRegister(offset, value);
        }
        super.writeHoldingRegister(offset, value);
    }

    @Override
    public void writeHoldingRegisterRange(int offset, int[] range) throws IllegalDataAddressException, IllegalDataValueException {
        logger.debug("writeHoldingRegisterRange");
        if (ConverterApplication.master != null) {
            ConverterApplication.master.writeHoldingRegisterRange(offset, dataConvert(range));
        }
        super.writeHoldingRegisterRange(offset, dataConvert(range));
    }

    @Override
    public void writeCoil(int offset, boolean value) throws IllegalDataAddressException, IllegalDataValueException {
        logger.debug("writeCoil");
        if (ConverterApplication.master != null) {
            ConverterApplication.master.writeCoil(offset, value);
        }
        super.writeCoil(offset, value);
    }

    @Override
    public void writeCoilRange(int offset, boolean[] range) throws IllegalDataAddressException, IllegalDataValueException {
        logger.debug("writeCoilRange");
        if (ConverterApplication.master != null) {
            ConverterApplication.master.writeCoilRange(offset, range);
        }
        super.writeCoilRange(offset, range);
    }

    /**
     * 数据转换
     * @param range
     * @return
     */
    private int[] dataConvert(int[] range){
        int[] newArr = new int[range.length * 2];
        byte[] bytes;
        int z = 0;
        for (int i = 0; i < range.length; i++) {
            bytes = DataUtils.toByteArray(range[i]);
            newArr[z] = DataUtils.toShort(bytes[2], bytes[3]);
            newArr[z + 1] = DataUtils.toShort(bytes[0], bytes[1]);
            z += 2;
        }
        return newArr;
    }

    /**
     * 写入本地
     *
     * @param offset
     * @param quantity
     * @param modbusHoldingRegisters
     */
    private void writeLocalOfRead(int offset, int quantity, ModbusHoldingRegisters modbusHoldingRegisters) {
        byte[] request = ConverterApplication.master.request(offset, quantity);
        int j = quantity - 1;
        for (int i = request.length - 1; i >= 0; i -= 2) {
            try {
                int v = DataUtils.toShort(request[i - 1], request[i]);
                modbusHoldingRegisters.setInt16At(offset + j, v);
            } catch (Exception e) {
                logger.debug(e.getMessage());
            }
            j--;
        }
    }
}
